import {
  ComponentPropsOptions,
  defineComponent,
  ExtractPropTypes,
  getCurrentInstance,
  inject,
  provide,
  SetupContext,
} from "vue";

export function designComponent<
  PropsOptions extends Readonly<ComponentPropsOptions>,
  Props extends Readonly<ExtractPropTypes<PropsOptions>>,
  Refer
>(options: {
  name?: string;
  props?: PropsOptions;
  provideRefer?: boolean;
  setup: (
    props: Props,
    setupContext: SetupContext
  ) => {
    refer?: Refer;
    render: () => any;
  };
}) {
  const { setup, provideRefer, ...leftOptions } = options;
  return {
    ...defineComponent({
      ...leftOptions,
      setup(props: Props, setupContext: SetupContext) {
        const ctx = getCurrentInstance() as any;
        if (!setup) {
          console.error("designComponent:setup is required");
          return () => null;
        }
        const { refer, render } = setup(props, setupContext);
        ctx._refer = refer;
        if (provideRefer) {
          if (!leftOptions.name) {
            console.error(
              "designComponent:name is required when provideRefer is true"
            );
          }
          provide(`@@${leftOptions.name}`, refer);
        }
        // ctx._refer = refer;
        return render;
      },
    } as any),
    use: {
      ref: (refName: string) => {
        const ctx = (getCurrentInstance() as any).ctx;
        return {
          get value() {
            return (ctx as any).$refs[refName].$._refer as Refer | null;
          },
        };
      },
      inject: (defaultValue?: any) => {
        return inject(`@@${leftOptions.name}`, defaultValue) as Refer;
      },
    },
  };
}

// const Button =designComponent({
//     name:'pl-button',
//     props:{
//         label:{type:String},
//         age:{type:Number,default:10},
//         flag:{type:Boolean,required:true}
//     },
//     setup(props,ctx){
//         return {
//             render:()=>{}
//         }
//     }
// })
